package com.dd.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 */
@Component
public class RedisUtil {
    
    private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class);

    @Value("${redis.enabled}")
    private boolean redisEnabled;

    @Autowired(required = false)
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 检查Redis是否启用
     */
    private boolean isRedisAvailable() {
        return redisEnabled && redisTemplate != null;
    }

    /**
     * 设置缓存
     */
    public boolean set(String key, Object value) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过设置缓存: {}", key);
            return false;
        }
        
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            logger.error("设置缓存失败: {}", key, e);
            return false;
        }
    }

    /**
     * 设置缓存并设置过期时间
     */
    public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过设置缓存: {}", key);
            return false;
        }
        
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, timeUnit);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            logger.error("设置缓存失败: {}", key, e);
            return false;
        }
    }

    /**
     * 获取缓存
     */
    public Object get(String key) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过获取缓存: {}", key);
            return null;
        }
        
        try {
            return key == null ? null : redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            logger.error("获取缓存失败: {}", key, e);
            return null;
        }
    }

    /**
     * 删除缓存
     */
    public boolean delete(String key) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过删除缓存: {}", key);
            return false;
        }
        
        try {
            return redisTemplate.delete(key);
        } catch (Exception e) {
            logger.error("删除缓存失败: {}", key, e);
            return false;
        }
    }

    /**
     * 批量删除缓存
     */
    public long delete(Set<String> keys) {
        if (!isRedisAvailable() || keys == null || keys.isEmpty()) {
            logger.debug("Redis未启用或keys为空，跳过批量删除缓存");
            return 0;
        }
        
        try {
            return redisTemplate.delete(keys);
        } catch (Exception e) {
            logger.error("批量删除缓存失败", e);
            return 0;
        }
    }

    /**
     * 设置过期时间
     */
    public boolean expire(String key, long time, TimeUnit timeUnit) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过设置过期时间: {}", key);
            return false;
        }
        
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            logger.error("设置过期时间失败: {}", key, e);
            return false;
        }
    }

    /**
     * 获取过期时间
     */
    public long getExpire(String key, TimeUnit timeUnit) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过获取过期时间: {}", key);
            return -2;
        }
        
        try {
            return redisTemplate.getExpire(key, timeUnit);
        } catch (Exception e) {
            logger.error("获取过期时间失败: {}", key, e);
            return -2;
        }
    }

    /**
     * 判断key是否存在
     */
    public boolean hasKey(String key) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过判断key是否存在: {}", key);
            return false;
        }
        
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            logger.error("判断key是否存在失败: {}", key, e);
            return false;
        }
    }

    /**
     * 按照模式获取key
     */
    public Set<String> keys(String pattern) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过按照模式获取key: {}", pattern);
            return Collections.emptySet();
        }
        
        try {
            return redisTemplate.keys(pattern);
        } catch (Exception e) {
            logger.error("按照模式获取key失败: {}", pattern, e);
            return Collections.emptySet();
        }
    }

    /**
     * 递增
     */
    public long increment(String key, long delta) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过递增操作: {}", key);
            return 0;
        }
        
        try {
            if (delta < 0) {
                throw new RuntimeException("递增因子必须大于0");
            }
            return redisTemplate.opsForValue().increment(key, delta);
        } catch (Exception e) {
            logger.error("递增操作失败: {}", key, e);
            return 0;
        }
    }

    /**
     * 递减
     */
    public long decrement(String key, long delta) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过递减操作: {}", key);
            return 0;
        }
        
        try {
            if (delta < 0) {
                throw new RuntimeException("递减因子必须大于0");
            }
            return redisTemplate.opsForValue().decrement(key, delta);
        } catch (Exception e) {
            logger.error("递减操作失败: {}", key, e);
            return 0;
        }
    }

    // Hash操作

    /**
     * 设置Hash
     */
    public boolean hashSet(String key, String hashKey, Object value) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过设置Hash: {}", key);
            return false;
        }
        
        try {
            redisTemplate.opsForHash().put(key, hashKey, value);
            return true;
        } catch (Exception e) {
            logger.error("设置Hash失败: {}", key, e);
            return false;
        }
    }

    /**
     * 获取Hash
     */
    public Object hashGet(String key, String hashKey) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过获取Hash: {}", key);
            return null;
        }
        
        try {
            return redisTemplate.opsForHash().get(key, hashKey);
        } catch (Exception e) {
            logger.error("获取Hash失败: {}", key, e);
            return null;
        }
    }

    /**
     * 获取Hash中所有键值对
     */
    public Map<Object, Object> hashGetAll(String key) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过获取Hash所有键值对: {}", key);
            return Collections.emptyMap();
        }
        
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            logger.error("获取Hash所有键值对失败: {}", key, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 删除Hash中的值
     */
    public boolean hashDelete(String key, Object... hashKeys) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过删除Hash中的值: {}", key);
            return false;
        }
        
        try {
            redisTemplate.opsForHash().delete(key, hashKeys);
            return true;
        } catch (Exception e) {
            logger.error("删除Hash中的值失败: {}", key, e);
            return false;
        }
    }

    // List操作

    /**
     * 获取List指定范围内的元素
     */
    public List<Object> listRange(String key, long start, long end) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过获取List范围: {}", key);
            return Collections.emptyList();
        }
        
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            logger.error("获取List范围失败: {}", key, e);
            return Collections.emptyList();
        }
    }

    /**
     * 获取List长度
     */
    public long listSize(String key) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过获取List长度: {}", key);
            return 0;
        }
        
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            logger.error("获取List长度失败: {}", key, e);
            return 0;
        }
    }

    /**
     * 将值放入List
     */
    public boolean listRightPush(String key, Object value) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过将值放入List: {}", key);
            return false;
        }
        
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            logger.error("将值放入List失败: {}", key, e);
            return false;
        }
    }

    /**
     * 将值放入List并设置过期时间
     */
    public boolean listRightPush(String key, Object value, long time, TimeUnit timeUnit) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过将值放入List并设置过期时间: {}", key);
            return false;
        }
        
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time, timeUnit);
            }
            return true;
        } catch (Exception e) {
            logger.error("将值放入List并设置过期时间失败: {}", key, e);
            return false;
        }
    }

    /**
     * 批量将值放入List
     */
    public boolean listRightPushAll(String key, List<Object> values) {
        if (!isRedisAvailable()) {
            logger.debug("Redis未启用，跳过批量将值放入List: {}", key);
            return false;
        }
        
        try {
            redisTemplate.opsForList().rightPushAll(key, values.toArray());
            return true;
        } catch (Exception e) {
            logger.error("批量将值放入List失败: {}", key, e);
            return false;
        }
    }
} 